2oneweek.dev

05. useState Hook

    Tags

  • React
05. useState Hook thumbnail

hook useState()

  • 상태값을 추가하기 위해 사용하는 훅
const App = () => { const [count, setCount] = useState(0); const onClick = () => { setCount(count + 1); setCount(count + 1); console.log(count); //변경되지 않은 이전의 값을 출력함 }; console.log("re-render"); return ( <div onClick={onClick}> <h1>{count}</h1> </div> ); };
  • useState는 배열을 반환한다. 첫 번째 아이템은 상태값, 두 번째 아이템은 상태값 변경 함수가 반환된다.
  • onClick() 에서 상태 값 변경 함수를 두 번 호출했지만, 클릭을 하면 2씩 증가하지 않고 1씩 증가한다.
    • 상태값 변경 함수는 비동기이면서 batch로 처리되기 때문에 의도한대로 동작하지 않는다. 리액트는 효율적인 렌더링을 위해 여러 개의 상태값 변경 요청을 배치batch로 처리한다.
    • 따라서 onClick 함수가 호출되어도 console.log(re-render)는 한 번만 출력될 것이다.




React State 비동기성

console.log(count) //=> 변경되지 않은 이전의 값을 출력함 이것은 State가 비동기적으로 처리됨을 의미한다.

  • 만약 동기 처리를 하게되면, 하나의 상태값 변경 함수가 호출될 때마다 화면을 다시 그리기 때문에 성능 이슈가 생길 수 있다.
  • React는 batch update를 16ms 단위로 진행한다. 16ms 동안 변경된 상태 값들을 모아서 단 한 번 리렌더링을 진행한다.
  • setState 이후 바로 상태값을 참조하여 다른 작업을 하려면 동기화가 필요한데, 이때 사용하는 것이 react-thunk, react-saga이다.




React State 일괄 처리

console.log(re-render) //=>setCount가 두 번 호출되었는데 한 번만 리렌더링 됨 이것은 React의 상태 변경이 batch 일괄 처리 됨을 의미한다.

  • React는 batch update를 16ms 단위로 진행한다. 16ms 동안 변경된 상태 값들을 모아서 단 한 번 리렌더링을 진행한다.
    • setCount가 처음 호출되더라도, 일괄처리가 일어나기 때문에, 두 번째 setCount에서 상태 값은 여전히 증가되지 않은 상태다. 따라서, 일괄 처리에 의해, 비동기에 의해 두 번 상태변경 함수를 처리해도 의미가 없다.
  • 만약 두 번 호출하는 것을 원한다면 상태값 변경 함수에 인자로 "함수"를 넣으면 된다. const onClick = () => { setCount((v) => v + 1); setCount((v) => v + 1); console.log(count); }; console.log("re-render");
    • 상태변경 함수의 함수는 인자로 처리되기 "직전"의 상태 값을 받게 되기 때문에 두 번 호출이 정상적으로 동작한다.

onClick 함수가 리액트 요소에 의해 호출될 때만 batch 처리가 된다. 만약 onClick 함수를 외부에서 호출하면, 일괄처리가 되지 않고 클릭이 발생할 때 마다 리-렌더링이 발생하게 된다. 외부 호출 또한 일괄처리를 하고 싶다면 ReactDOM.unstable_batchedUpdate()라는 메소드를 사용하면 된다.





객체 State

const App = () => { const [state, setState] = useState({ name: "이한주", age: 27 }); const onClick = () => { //setState(state.age + 1) setState({ ...state, age: state.age + 1 }); }; };
  • 클릭을 할 때, state의 프로퍼티 age의 값은 바뀐다.
  • 그러나 상태가 객체일 경우에는 State는 참조값을 갖게된다.
  • 따라서 내부 값이 변하더라도, State의 참조값은 변경되지 않으므로 상태 변화를 리액트가 감지할 수 없고 리렌더링 되지 않는다.
  • 객체를 새로 만들어 할당해야 이 문제를 해결할 수 있다.

    그러나, 이렇게 여러 상태를 객체로 묶어 관리할 때는 useState보다, useReducer라는 훅이 더 적합하다.

Written by@2-one-week
현재 블로그 개발 중

GitHubLinkedIn